package cn.gs.exchanger;

// @author gs
import cn.gs.serializable.old.SerializableTool;
import cn.gs.util.net.SocketAgent;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;

public class ExchangerCommand {

    public enum SystemCommand {

        ALL_SERVICE("~ALL"), SERVICE_PROVIDER_COUNT("~CNT"),
        REGISTER("~REG"), UNIQUE("~UNI"), DELETE("~DEL"),
        ANSWER("~ANS"), ERROR("~ERR");
        private String server;

        private SystemCommand(String server) {
            this.server = server;
        }

        public String getServer() {
            return server;
        }
    }
    private String number;
    private String server;
    private String args;

    public boolean isSystemCommand() {
        for (SystemCommand sys : SystemCommand.values()) {
            if (this.match(sys)) {
                return true;
            }
        }
        return false;
    }

    public String toString() {
        return number + " " + encode(server) + " " + (args == null ? "" : args);
    }

    public ExchangerCommand replayAnswer(List<String> o) {
        return new ExchangerCommand(number, SystemCommand.ANSWER.getServer(), o);
    }

    public ExchangerCommand replayAnswer(String... o) {
        return new ExchangerCommand(number, SystemCommand.ANSWER.getServer(), o);
    }

    public ExchangerCommand replayError(List<String> o) {
        return new ExchangerCommand(number, SystemCommand.ERROR.getServer(), o);
    }

    public ExchangerCommand replayError(String... o) {
        return new ExchangerCommand(number, SystemCommand.ERROR.getServer(), o);
    }

    public ExchangerCommand(String number, SystemCommand server, String... args) {
        this(number, server.getServer(), Arrays.asList(args));
    }

    public ExchangerCommand(String number, SystemCommand server, List<String> args) {
        this(number, server.getServer(), args);
    }

    public ExchangerCommand(String number, String server, String... args) {
        this(number, server, Arrays.asList(args));
    }

    public ExchangerCommand(String number, String server, List<String> args) {
        this.number = number;
        this.server = server;
        boolean flag = false;
        StringBuilder sb = new StringBuilder();
        for (String s : args) {
            if (s != null) {
                if (flag) {
                    sb.append(" ");
                } else {
                    flag = true;
                }
                sb.append(encode(s));
            }
        }
        this.args = sb.toString();
    }

    public ExchangerCommand(String msg) {
        if (msg != null) {
            StringTokenizer st = new StringTokenizer(msg, " ");
            //Number ServerName Args
            this.number = st.nextToken();
            this.server = decode(st.nextToken());
            if (number.length() + server.length() + 1 < msg.length()) {
                this.args = msg.substring(number.length() + server.length() + 2);
            } else {
                this.args = "";
            }
        }
    }

    public boolean match(SystemCommand sys) {
        return (sys != null && sys.getServer().equals(getServer()));
    }

    public void sendTo(SocketAgent agent) throws IOException {
        agent.writeLine(this.toString());
    }

    public String getNumber() {
        return number;
    }

    public String getServer() {
        return server;
    }

    public String getArgs() {
        return args;
    }

    public List<String> getArgsList() {
        StringTokenizer st = new StringTokenizer(args, " ");
        List<String> ls = new LinkedList<String>();
        while (st.hasMoreTokens()) {
            ls.add(decode(st.nextToken()));
        }
        return ls;
    }

    private static String encode(String str) {
        return str.replace("\\", "\\\\").replace(" ", "\\s").replace("\n", "\\n");
    }

    private static String decode(String str) {
        return str.replace("\\\\", "\\m").replace("\\n", "\n").replace("\\s", " ").replace("\\m", "\\");
    }
}
